#include "node.h"

namespace sfc::serde {

Node::Node() : _inn{Null{}} {}

Node::~Node() = default;

Node::Node(Node&&) noexcept = default;

Node& Node::operator=(Node&&) noexcept = default;

Node::Node(bool val) : _inn{val} {}

Node::Node(i32 val) : _inn{static_cast<i64>(val)} {}

Node::Node(u32 val) : _inn{static_cast<i64>(val)} {}

Node::Node(i64 val) : _inn{static_cast<i64>(val)} {}

Node::Node(u64 val) : _inn{static_cast<i64>(val)} {}

Node::Node(f64 val) : _inn{val} {}

Node::Node(Str val) : _inn{String{val}} {}

Node::Node(cstr_t val) : _inn{String{val}} {}

Node::Node(List val) : _inn{static_cast<List&&>(val)} {}

Node::Node(Dict val) : _inn{static_cast<Dict&&>(val)} {}

auto Node::as_null() const -> Option<Null> {
  return _inn.as<Null>().map([](auto& x) { return x; });
}

auto Node::as_bool() const -> Option<bool> {
  return _inn.as<bool>().map([](auto& x) { return x; });
}

auto Node::as_int() const -> Option<i64> {
  return _inn.as<i64>().map([](auto& x) { return x; });
}

auto Node::as_flt() const -> Option<f64> {
  return _inn.as<f64>().map([](auto& x) { return x; });
}

auto Node::as_str() const -> Option<Str> {
  auto ret = _inn.as<String>().map([](auto& x) { return x.as_str(); });
  return ret;
}

auto Node::as_list() const -> Option<const List&> {
  return _inn.as<List>();
}

auto Node::as_dict() const -> Option<const Dict&> {
  return _inn.as<Dict>();
}

auto Node::len() const -> usize {
  return _inn.map([](auto& x) {
    if constexpr (requires { x.len(); }) {
      return x.len();
    }
    return 0UL;
  });
}

auto Node::operator[](usize idx) const -> const Node& {
  auto& list = _inn.as<List>().unwrap();
  return list[idx];
}

void Node::push(Node val) {
  auto& list = _inn.as_mut<List>().unwrap();
  list.push(mem::move(val));
}

auto Node::operator[](Str key) const -> const Node& {
  auto& dict = _inn.as<Dict>().unwrap();
  return dict[key];
}

void Node::insert(Str key, Node val) {
  auto& dict = _inn.as_mut<Dict>().unwrap();
  dict.insert(String{key}, static_cast<Node&&>(val));
}

}  // namespace sfc::serde
